package com.ruoyi.basedata.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctg.ag.sdk.biz.AepDeviceCommandClient;
import com.ctg.ag.sdk.biz.AepDeviceManagementClient;
import com.ctg.ag.sdk.biz.aep_device_command.CreateCommandRequest;
import com.ctg.ag.sdk.biz.aep_device_command.CreateCommandResponse;
import com.ctg.ag.sdk.biz.aep_device_command.QueryCommandRequest;
import com.ctg.ag.sdk.biz.aep_device_command.QueryCommandResponse;
import com.ctg.ag.sdk.biz.aep_device_management.*;
import com.ruoyi.basedata.domain.*;
import com.ruoyi.basedata.domain.vo.ElectricityTerminalsXbProtocol;
import com.ruoyi.basedata.mapper.*;
import com.ruoyi.basedata.service.IElectricityTerminalsXbService;
import com.ruoyi.basedata.service.ITerminalsXbService;
import com.ruoyi.basedata.wxentity.AreaTreeTerminalInfo;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ExceptionUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.SnowflakeUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 小档案Service业务层处理
 *
 * @author ruoyi
 * @date 2023-09-07
 */
@Service
@Slf4j
public class ElectricityTerminalsXbServiceImpl extends ServiceImpl<ElectricityTerminalsXbMapper, ElectricityTerminalsXb> implements IElectricityTerminalsXbService {
    @Autowired
    private ElectricityTerminalsXbMapper terminalsXbMapper;

    @Autowired
    private RoomMapper roomMapper;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ProtocolMapper protocolMapper;

    @Autowired
    private ElectricityConcentratorMapper concentratorMapper;

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private MeterSheetsMapper meterSheetsMapper;

    @Autowired
    private ReplaceMapper replaceMapper;

    @Autowired
    private ElectricityUsersXbMapper usersXbMapper;

    @Autowired
    private UserChangeXbLogMapper userChangeXbLogMapper;

    @Value("${system-params.appKey}")
    public String appKey;
    //    @Value("${system-params.appSecret}")
    @Value("${system-params.appSecret}")
    private String appSecret;
    @Value("${system-params.masterKey}")
    private String masterKey;
    @Value("${system-params.productId}")
    private String productId;

    private static String factoryCode = "1002";

    private static String guoxin_NB_url = "https://2000110932.api.ctwing.cn/aep_device_management/device";

    private static String guoxin_MasterKey = "7e8e66f383e84f3bb65cd248e7d4a435";

//    private static String secret = "FJDq8agNp5";//密钥，到控制台->应用管理打开应用可以找到此值
//    private static String application = "91Ebv1S0HBb";//appKey，到控制台->应用管理打开应用可以找到此值
//    private static String version = "20181031202117";//api版本，到文档中心->使能平台API文档打开要调用的api可以找到版本值
//    private static String MasterKey = "25ce00cc28c1498c833276110ee483f0";//MasterKey，在产品中心打开对应的产品查看此值

    /**
     * 查询小档案
     *
     * @param ID 小档案主键
     * @return 小档案
     */
    @Override
    public ElectricityTerminalsXb selectTerminalsXbByID(Long ID) {
        return terminalsXbMapper.selectTerminalsXbByID(ID);
    }

    /**
     * 查询小档案列表
     *
     * @param terminalsXb 小档案
     * @return 小档案
     */
    @Override
    public List<ElectricityTerminalsXb> selectTerminalsXbList(ElectricityTerminalsXb terminalsXb) {
        return terminalsXbMapper.selectTerminalsXbList(terminalsXb);
    }
 @Override
    public List<ElectricityTerminalsXb> selectTerminalsXbListAll(ElectricityTerminalsXb terminalsXb) {
        return terminalsXbMapper.selectTerminalsXbListAll(terminalsXb);
    }

    /**
     * 根据通讯地址、厂家编码查询设备
     *
     * @param terminalsXb
     * @return
     */
    @Override
    public List<ElectricityTerminalsXbProtocol> selectTerminalsXbProtocolList(ElectricityTerminalsXb terminalsXb) {
        return terminalsXbMapper.selectTerminalsXbProtocolList(terminalsXb);
    }

    /**
     * 新增小档案
     *
     * @param terminalsXb 小档案
     * @return 结果
     */
    @Override
    public String insertTerminalsXb(ElectricityTerminalsXb terminalsXb) {
        List<ElectricityTerminalsXb> terminalsXbs1 = terminalsXbMapper.selectList(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                .eq(terminalsXb.getTerminalId() != null, ElectricityTerminalsXb::getTerminalId, terminalsXb.getTerminalId()));
        if (terminalsXbs1.size() > 0) {
            return "设备编号已存在";
        }
        if (terminalsXb.getImei() != null && !"".equals(terminalsXb.getImei())) {
            List<ElectricityTerminalsXb> terminalsXbs2 = terminalsXbMapper.selectList(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                    .eq(terminalsXb.getImei() != null, ElectricityTerminalsXb::getImei, terminalsXb.getImei()));
            if (terminalsXbs2.size() > 0) {
                return "IMEI号已存在";
            }
        }
//        List<ElectricityTerminalsXb> terminalsXbs3 = terminalsXbMapper.selectList(new LambdaQueryWrapper<ElectricityTerminalsXb>()
//                .eq(terminalsXb.getCommunicateAddress() != null, ElectricityTerminalsXb::getCommunicateAddress, terminalsXb.getCommunicateAddress()));
//        if (terminalsXbs3.size() > 0){
//            return "通讯地址已存在";
//        }
        SnowflakeUtils snowflakeUtils = new SnowflakeUtils(0, 0);
        String locationNb = String.valueOf(snowflakeUtils.nextId());
        terminalsXb.setLocationNb(locationNb);
        terminalsXb.setDelFlag(0);
        terminalsXb.setTerminalMark(1);
        terminalsXb.setChangeMark(0);
        SysUser user = SecurityUtils.getLoginUser().getUser();
        terminalsXb.setCreateBy(user.getUserName());
        terminalsXb.setCreateTime(new Date());
        if (Objects.equals(terminalsXb.getProtocolId(), QIANBAOTONG_PROTOCOL_ID)) {
            // 千宝通协议需要额外增加表序号
            int maxSeq = terminalsXbMapper.selectMaxMeterSeq(QIANBAOTONG_PROTOCOL_ID, terminalsXb.getConcentratorId());
            int meterSeq = maxSeq + 1;
            terminalsXb.setMeterSeq(meterSeq);
            terminalsXb.setCommunicateAddress(terminalsXb.getConcentratorId() + "-" + meterSeq);
        }
        int flag = terminalsXbMapper.insertTerminalsXb(terminalsXb);
        if (flag > 0) {

            return "新增成功";
        } else {
            return "新增失败";
        }

    }

    /**
     * 修改小档案
     *
     * @param terminalsXb 小档案
     * @return 结果
     */
    @Override
    public String updateTerminalsXb(ElectricityTerminalsXb terminalsXb) {
        ElectricityTerminalsXb terminalsXb1 = terminalsXbMapper.selectOne(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                .eq(ElectricityTerminalsXb::getTerminalId, terminalsXb.getTerminalId())
                .eq(ElectricityTerminalsXb::getTerminalMark, 1)
                .last("limit 1"));
        ElectricityTerminalsXb terminalsXb2 = terminalsXbMapper.selectOne(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                .eq(ElectricityTerminalsXb::getImei, terminalsXb.getImei())
                .eq(ElectricityTerminalsXb::getTerminalMark, 1)
                .last("limit 1"));
        ElectricityTerminalsXb terminalsXb3 = terminalsXbMapper.selectOne(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                .eq(ElectricityTerminalsXb::getCommunicateAddress, terminalsXb.getCommunicateAddress())
                .eq(ElectricityTerminalsXb::getTerminalMark, 1)
                .last("limit 1"));
        if (terminalsXb1 != null && !terminalsXb.getId().equals(terminalsXb1.getId())) {
            return "该设备编号已存在";
        }
        if (terminalsXb2 != null && !terminalsXb.getId().equals(terminalsXb2.getId())) {
            return "该IMEI号已存在";
        }
        if (terminalsXb3 != null && !terminalsXb.getId().equals(terminalsXb3.getId())) {
            return "该通讯地址已存在";
        }
        SysUser user = SecurityUtils.getLoginUser().getUser();
        terminalsXb.setUpdateBy(user.getUserName());
        terminalsXb.setUpdateTime(new Date());
        if (Objects.equals(terminalsXb.getProtocolId(), QIANBAOTONG_PROTOCOL_ID)) {
            // 千宝通协议不能在页面更改表序号和表通讯地址
            terminalsXb.setCommunicateAddress(null);
            ElectricityTerminalsXb old = terminalsXbMapper.selectById(terminalsXb.getId());
            if (!Objects.equals(terminalsXb.getConcentratorId(), old.getConcentratorId())) {
                int maxSeq = terminalsXbMapper.selectMaxMeterSeq(QIANBAOTONG_PROTOCOL_ID, terminalsXb.getConcentratorId());
                int meterSeq = maxSeq + 1;
                terminalsXb.setMeterSeq(meterSeq);
                terminalsXb.setCommunicateAddress(terminalsXb.getConcentratorId() + "-" + meterSeq);
            }
        }
        int flag = terminalsXbMapper.updateTerminalsXb(terminalsXb);
        if (flag > 0) {
            ElectricityTerminalsXbProtocol terminalsXbProtocol = new ElectricityTerminalsXbProtocol();
            terminalsXbProtocol.setImei(terminalsXb.getImei());
            List<ElectricityTerminalsXbProtocol> terminalsXbProtocols = selectTerminalsXbProtocolList(terminalsXbProtocol);
            if (terminalsXbProtocols.size() != 0) {
                redisCache.setCacheMapValue(RedisKeyName.terminalInfo + terminalsXbProtocols.get(0).getSupplierId(), terminalsXbProtocols.get(0).getCommunicateAddress(), terminalsXbProtocols.get(0));
            }
            return "更新成功";
        } else {
            return "更新失败";
        }
    }

    /**
     * 批量删除小档案
     *
     * @param IDs 需要删除的小档案主键
     * @return 结果
     */
    @Override
    public int deleteTerminalsXbByIDs(Long[] IDs) throws Exception {
        List<ElectricityTerminalsXb> terminalsXbs = terminalsXbMapper.selectBatchIds(Arrays.asList(IDs));
        int flag = terminalsXbMapper.deleteBatchIds(Arrays.asList(IDs));
        List<String> deviceIds = terminalsXbs.stream().filter(terminalsXb -> terminalsXb.getProtocolId() != null && terminalsXb.getProtocolId().equals("2")).map(ElectricityTerminalsXb::getDeviceId).collect(Collectors.toList());
        JSONObject jsonObject = deleteGuoXinDeviceInAep(appKey, appSecret, masterKey, deviceIds, productId);
        log.info("删除AEP设备返回结果：{}", jsonObject);
        return flag;
    }

    /**
     * 删除小档案信息
     *
     * @param ID 小档案主键
     * @return 结果
     */
    @Override
    public int deleteTerminalsXbByID(Long ID) {
        return terminalsXbMapper.deleteTerminalsXbByID(ID);
    }

    @Override
    public List<ElectricityTerminalsXb> selectlistNoBound() {
        return terminalsXbMapper.selectList(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                .isNull(ElectricityTerminalsXb::getTerminalId));
    }

    @Override
    public int logout(Long id) {
        ElectricityTerminalsXb terminalsXb = terminalsXbMapper.selectTerminalsXbByID(id);
        terminalsXb.setTerminalMark(0);
        return terminalsXbMapper.updateTerminalsXb(terminalsXb);
    }

    @Override
    public List<ElectricityTerminalsXb> selectListByAreaCode(String treeAreaCode) {

        return terminalsXbMapper.selectListByAreaCode(treeAreaCode);
    }

    @Override
    public List<ElectricityTerminalsXb> selectListByLdId(String treeLdId) {
        return terminalsXbMapper.selectListByLdId(treeLdId);
    }

    // 根据不同的平台，走不同的平台注册
    @Override
    public String importUser(List<ElectricityTerminalsXb> list, boolean updateSupport, String operName) {
        if (StringUtils.isNull(list) || list.isEmpty()) {
            throw new ServiceException("导入设备数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        for (ElectricityTerminalsXb terminalsXb : list) {
            try {
                // 验证是否存在这个表用户
                List<ElectricityTerminalsXb> terminalsXbsList = terminalsXbMapper.selectList(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                        .eq(ElectricityTerminalsXb::getTerminalId, terminalsXb.getTerminalId())
                        .eq(ElectricityTerminalsXb::getDelFlag, 0));
                List<ElectricityTerminalsXb> terminalsXbs2 = null;
                MeterSheets meterSheets = meterSheetsMapper.selectOne(new LambdaQueryWrapper<MeterSheets>()
                        .eq(MeterSheets::getSheetsCode, terminalsXb.getSheetsCode())
                        .eq(MeterSheets::getDelFlag, 0));
                if (terminalsXb.getImei() != null && !"".equals(terminalsXb.getImei())) {
                    terminalsXbs2 = terminalsXbMapper.selectList(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                            .eq(terminalsXb.getImei() != null, ElectricityTerminalsXb::getImei, terminalsXb.getImei()));
                }
                Protocol protocol = null;
                if (terminalsXb.getProtocolName() != null && !"".equals(terminalsXb.getProtocolName())) {
                    protocol = protocolMapper.selectOne(new LambdaQueryWrapper<Protocol>()
                            .eq(Protocol::getProtocolName, terminalsXb.getProtocolName()));
                }

                if (terminalsXb.getSupplierId().isEmpty()) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、厂家编号不能为空 ");
                    continue;
                } else if (null != terminalsXbsList && terminalsXbsList.size() > 0) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsXb.getTerminalId()).append(" 已存在");
                } else if (terminalsXb.getImei() != null && !"".equals(terminalsXb.getImei()) && null != terminalsXbs2 && terminalsXbs2.size() > 0) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、IMEI ").append(terminalsXb.getImei()).append(" 已存在");
                } else if (terminalsXb.getProtocolName() != null && !"".equals(terminalsXb.getProtocolName()) && protocol == null) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、通讯协议 ").append(terminalsXb.getProtocolName()).append(" 不存在");
                } else if (meterSheets == null) {
                    failureNum++;
                    failureMsg.append("<br/>").append(failureNum).append("、区域编号 ").append(terminalsXb.getSheetsCode()).append(" 不存在");
                } else {
                    if (protocol != null) {
                        terminalsXb.setProtocolId(protocol.getProtocolId());
                    }
                    terminalsXb.setSheetsId(meterSheets.getId().intValue());
                    SnowflakeUtils snowflakeUtils = new SnowflakeUtils(0, 0);
                    String locationNb = String.valueOf(snowflakeUtils.nextId());
                    terminalsXb.setLocationNb(locationNb);
                    terminalsXb.setInstallAddress(terminalsXb.getRoomName());
                    if (Objects.equals(terminalsXb.getProtocolId(), QIANBAOTONG_PROTOCOL_ID)) {
                        // 千宝通协议需要额外增加表序号
                        int maxSeq = terminalsXbMapper.selectMaxMeterSeq(QIANBAOTONG_PROTOCOL_ID, terminalsXb.getConcentratorId());
                        int meterSeq = maxSeq + 1;
                        terminalsXb.setMeterSeq(meterSeq);
                        terminalsXb.setCommunicateAddress(terminalsXb.getConcentratorId() + "-" + meterSeq);
                    }
                    int sucessCount = terminalsXbMapper.insertTerminalsXb(terminalsXb);
                    // 更新redis
                    if (sucessCount > 0) {
                        try {
                            List<ElectricityTerminalsXbProtocol> terminalsXbProtocols = selectTerminalsXbProtocolList(terminalsXb);
                            if (!terminalsXbProtocols.isEmpty()) {
                                redisCache.setCacheMapValue(RedisKeyName.terminalInfo + terminalsXbProtocols.get(0).getSupplierId(), terminalsXbProtocols.get(0).getCommunicateAddress(), terminalsXbProtocols.get(0));
                            }
                        } catch (Exception e) {
                            log.error("户表插入redis失败,设备编号：{}", terminalsXb.getTerminalId());
                            log.error(ExceptionUtil.getExceptionMessage(e));
                        }
                    }

                    successNum++;
                    successMsg.append("<br/>").append(successNum).append("、设备编号 ").append(terminalsXb.getTerminalId()).append(" 导入成功");
                    if (terminalsXb.getConcentratorId() != null) {// 判断是否是挂在集中器下的户表
                        continue;
                    }
                    try {
                        if (terminalsXb.getProtocolId() == null || !"2".equals(terminalsXb.getProtocolId())) {
                            failureNum++;
                            failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsXb.getTerminalId()).append(" 导入成功,协议错误,不能注册");
                        } else {

                            JSONObject responseBody = null;
                            // 做一个sign标识来确定走的是哪一个的返回值
                            String sign = null;
                            if (terminalsXb.getSignPlatform() == null) {
                                failureNum++;
                                failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsXb.getTerminalId()).append("请选择正确的注册平台");
//                                throw new RuntimeException("请选择OneNET平台或aep平台");
                            }
                            // 用sign来判断它走aep还是onenet
                            if (terminalsXb.getSignPlatform() == 2) {
                                sign = "OneNET";
                                responseBody = createDeviceInOneNet(terminalsXb);
                            } else if (terminalsXb.getSignPlatform() == 1) {
                                sign = "aep";
                                responseBody = createGuoXinDeviceInAep(appKey, appSecret, masterKey, terminalsXb);
                            } else if (terminalsXb.getSignPlatform() == 3) {
                                sign = "netty";
                                // netty平台暂时不要做什么操作
                            }
                            // aep返回码是code，onenet返回码是errno，所以分来来写
                            if (responseBody == null && sign == null) {
                                failureNum++;
                                failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsXb.getTerminalId()).append("导入成功,发送注册请求到物联网平台时出现错误，注册失败");
                            } else if (responseBody != null) {
                                if ("aep".equals(sign)) {
                                    if (Integer.parseInt(responseBody.getString("code")) == 0) {
                                        successMsg.append(",").append(sign).append("平台注册成功");
                                        String deviceId = JSONObject.parseObject(responseBody.getString("result")).getString("deviceId");
                                        ElectricityTerminalsXb terminalsXb1 = terminalsXbMapper.selectOne(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                                                .eq(ElectricityTerminalsXb::getImei, terminalsXb.getImei()));
                                        terminalsXb1.setDeviceId(deviceId);
                                        terminalsXbMapper.updateTerminalsXb(terminalsXb1);
                                    } else {
                                        failureNum++;
                                        failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsXb.getTerminalId()).append(" 导入成功,").append(sign).append("平台注册失败 ").append(responseBody.getString("msg"));
                                    }
                                }

                                if ("OneNET".equals(sign)) {
                                    if (Integer.parseInt(responseBody.getString("errno")) == 0) {
                                        successMsg.append(",").append(sign).append("平台注册成功");
                                        String deviceId = JSONObject.parseObject(responseBody.getString("data")).getString("device_id");
                                        ElectricityTerminalsXb terminalsXb1 = terminalsXbMapper.selectOne(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                                                .eq(ElectricityTerminalsXb::getImei, terminalsXb.getImei()));
                                        terminalsXb1.setDeviceId(deviceId);
                                        terminalsXbMapper.updateTerminalsXb(terminalsXb1);
                                    } else {
                                        failureNum++;
                                        failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsXb.getTerminalId()).append(" 导入成功,").append(sign).append("平台注册失败 ").append(responseBody.getString("error"));
                                    }
                                }
                            }
                        }
                    } catch (Exception e) {
                        failureNum++;
                        failureMsg.append("<br/>").append(failureNum).append("、设备编号 ").append(terminalsXb.getTerminalId()).append(" 导入成功,物联网平台注册失败");
                    }
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、设备编号 " + terminalsXb.getTerminalId() + " 导入失败：";
                failureMsg.append(msg).append(e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public ElectricityTerminalsXbProtocol getcreateCommandParm(Integer commandType, String isOpen, ElectricityTerminalsXbProtocol terminalsXbProtocol) {
        String terminalAdd = "";
        JSONObject jsonObject = new JSONObject();
        ElectricityTerminalsXbProtocol terminalsXbProtocol1 = new ElectricityTerminalsXbProtocol();
        try {
            // if (!redisCache.hmhave(RedisKeyName.terminalInfo + factoryCode, terminalsXbProtocol.getCommunicateAddress()))//redis中是否存在该设备
            // {
            //
            List<ElectricityTerminalsXbProtocol> terminalsXbProtocols = selectTerminalsXbProtocolList(terminalsXbProtocol);
            if (terminalsXbProtocols.size() == 0) {
                // 记录异常
                redisCache.lPush(RedisKeyName.exceptions + terminalsXbProtocol.getSupplierId() + terminalAdd, terminalsXbProtocol.getCommunicateAddress());
                return null;
            } else {
                terminalsXbProtocol1 = terminalsXbProtocols.get(0);
                // 存入redis
                redisCache.setCacheMapValue(RedisKeyName.terminalInfo + terminalsXbProtocol1.getSupplierId(), terminalsXbProtocol1.getCommunicateAddress(), terminalsXbProtocol1);
            }
            // } else {
            //     terminalsXbProtocol1 = redisCache.getCacheMapValue(RedisKeyName.terminalInfo + factoryCode, terminalsXbProtocol.getCommunicateAddress());
            // }
            return terminalsXbProtocol1;
        } catch (Exception e) {
            // 记录异常
            redisCache.lPush(RedisKeyName.exceptions + terminalsXbProtocol.getSupplierId() + terminalAdd, terminalsXbProtocol.getCommunicateAddress());
            // 删除exceptions数据
            redisCache.trim(RedisKeyName.exceptions + terminalsXbProtocol.getSupplierId() + terminalAdd, -4, -1);
            return null;
        }
    }

    @Override
    public boolean sendCreateCommand(JSONObject jsonObject, String appKey, String appSecret, String masterKey) throws Exception {
        // 发送请求
        AepDeviceCommandClient client = AepDeviceCommandClient.newClient()
                .appKey(appKey).appSecret(appSecret)
                .build();
        try {
            CreateCommandRequest createCommandRequest = new CreateCommandRequest();
            log.info("发送AEP请求，请求报文：{}", jsonObject);
            log.info("appKey：{}，appSecret：{}，masterKey：{}", appKey, appSecret, masterKey);
            // set your request params here
            // single value
            createCommandRequest.setParamMasterKey(masterKey);
            // 具体格式见前面请求body说明
            createCommandRequest.setBody(jsonObject.toString().getBytes(StandardCharsets.UTF_8));
            CreateCommandResponse response = client.CreateCommand(createCommandRequest);
            String responseBody = new String(response.getBody(), StandardCharsets.UTF_8);
            log.info("本机默认字符集：{}", Charset.defaultCharset().name());
            log.info("AEP请求响应：{}", JSON.toJSONString(response));
            log.info("发送AEP请求，响应体：{}", responseBody);
            if (response.getStatusCode() != HttpStatus.SUCCESS) {
                log.error("发送AEP请求失败");
                return false;
            }
            JSONObject responseBodyJsonObject = JSONObject.parseObject(responseBody);
            return Objects.equals(responseBodyJsonObject.getInteger("code"), 0);
        } catch (Exception e) {
            log.error("发送创建命令请求时出错", e);
            return false;
        } finally {
            client.shutdown();
        }
    }

    /**
     * 通过onenet进行命令下发
     *
     * @param tp
     * @param payload
     * @return
     */
    @Override
    public boolean sendCreateCommandInOneNet(ElectricityTerminalsXbProtocol tp, String payload) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            long time = 24 * 60 * 60 * 1000;// 60分钟
            Date now = new Date();
            Date afterDate = new Date(now.getTime() + time);
            String format = sdf.format(afterDate).replace(" ", "T");
            System.out.println(format);
            JSONArray objects = new JSONArray();
            JSONObject data = new JSONObject();
            data.put("res_id", 5527);
            data.put("val", payload);
            objects.add(data);
            JSONObject params = new JSONObject();
            params.put("imei", tp.getImei());
            params.put("obj_id", 3341);
            params.put("obj_inst_id", 0);
            params.put("mode", 1);
            params.put("res_id", 5527);
            params.put("retry", 10);
            params.put("data", objects);
            params.put("expired_time", format);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("imei", tp.getImei());
            jsonObject.put("obj_id", 3341);
            jsonObject.put("mode", 1);
            jsonObject.put("res_id", 5527);
            jsonObject.put("obj_inst_id", 0);
            jsonObject.put("expired_time", format);
            jsonObject.put("retry", 10);
//            args.put("args", payload);//命令参数
//            String url = "https://iot-api.heclouds.com/nb-iot/execute";
            String url = "https://iot-api.heclouds.com/nb-iot/offline";
//            String url = "https://iot-api.heclouds.com/nb-iot";
            String sendPost = HttpUtils.sendPostWithToken(url, jsonObject, params);
            JSONObject json = JSONObject.parseObject(sendPost);
            System.out.println(json.toString());
            if (json.get("code").equals(0) && json.get("msg").equals("succ")) {
                return true;
            }
            return false;
        } catch (Exception e) {
            log.info("oneNET平台注册失败" + e.getMessage());
        }
        return false;
    }


    @Override
    public JSONObject queryCommand(String appKey, String appSecret, String MasterKey, String commandId, String deviceId) throws Exception {
        AepDeviceCommandClient client = AepDeviceCommandClient.newClient()
                .appKey(appKey).appSecret(appSecret)
                .build();
        QueryCommandRequest request = new QueryCommandRequest();
        request.setParamDeviceId(deviceId);
        request.setParamCommandId(commandId);
        request.setParamProductId(productId);
        // set your request params here
        request.setParamMasterKey(MasterKey);
        QueryCommandResponse queryCommandResponse = client.QueryCommand(request);
        client.shutdown();
        return JSONObject.parseObject(new String(queryCommandResponse.getBody(), StandardCharsets.UTF_8));
    }


    // 通过aep进行设备的添加注册
    @Override
    public JSONObject createGuoXinDeviceInAep(String appKey, String appSecret, String MasterKey, ElectricityTerminalsXb terminalsXb) {
        AepDeviceManagementClient client = AepDeviceManagementClient.newClient()
                .appKey(appKey).appSecret(appSecret)
                .build();
        try {
            CreateDeviceRequest request = new CreateDeviceRequest();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("deviceName", terminalsXb.getCommunicateAddress());
            jsonObject.put("deviceSn", terminalsXb.getImei());
            jsonObject.put("imei", terminalsXb.getImei());
            jsonObject.put("operator", SecurityUtils.getLoginUser().getUsername());
            jsonObject.put("productId", productId);
            Map<String, Object> other = new HashMap<>();
            other.put("autoObserver", 0);
            jsonObject.put("other", other);
            request.setParamMasterKey(MasterKey);
            request.setBody(jsonObject.toString().getBytes());
            CreateDeviceResponse createDeviceResponse = client.CreateDevice(request);
            System.out.println(createDeviceResponse);
            return JSONObject.parseObject(new String(createDeviceResponse.getBody(), StandardCharsets.UTF_8));
        } catch (Exception e) {
            log.info("aep平台注册失败" + e.getMessage());
            return null;
        } finally {
            client.shutdown();
        }
    }


    @Override
    // 通过中国移动开放物联网平台进行设备的添加
    public JSONObject createDeviceInOneNet(ElectricityTerminalsXb terminalsXb) {
        if (terminalsXb.getImsi().isEmpty())
            return null;
        try {
            JSONObject jsonOb = new JSONObject();
            jsonOb.put(terminalsXb.getImei(), terminalsXb.getImsi());// imsi&imei
            JSONObject object1 = new JSONObject();
//        object1.put("lon",100);//经度
//        object1.put("lat",25.31);//纬度
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("protocol", "LWM2M");// onenet接口协议,必须
            jsonObject.put("auth_info", jsonOb);// imei,imsi码,必须
            jsonObject.put("title", terminalsXb.getCommunicateAddress());// 设备名称,必须
//            jsonObject.put("location",object1);
            String url = "https://api.heclouds.com/devices";// 添加设备的接口地址
            String sendPost = HttpUtils.sendPostWithToken(url, jsonObject);
            JSONObject json = JSONObject.parseObject(sendPost);
            System.out.println(json.toString());
            if (json.get("errno").equals(0) && json.get("error").equals("succ")) {
                return json;
            }
            if (json.get("errno").equals(6)) {
                return json;
            }
        } catch (Exception e) {
            log.info("oneNET平台注册失败" + e.getMessage());
        }
        return null;
    }


    // 根据不同的值，走不同的平台注册
    @Override
    public String importDeviceInAep(List<ElectricityTerminalsXb> terminalsXbList) throws Exception {

        if (StringUtils.isNull(terminalsXbList) || terminalsXbList.size() == 0) {
            log.info("批量注册数据为空");
            throw new ServiceException("导入数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        // 用一个boolean类型来确定是否需要执行注册
        boolean bl = true;
        for (ElectricityTerminalsXb terminalsXb1 : terminalsXbList) {
            log.info("开始进入循坏");
            try {
                ElectricityTerminalsXb terminalsXb = terminalsXbMapper.selectOne(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                        .eq(ElectricityTerminalsXb::getImei, terminalsXb1.getImei()));
                if (terminalsXb.getDeviceId() != null && !terminalsXb.getDeviceId().equals("")) {
                    failureNum++;
                    bl = false;
                    failureMsg.append("</br>" + failureNum + ",IMEI" + terminalsXb.getImei() + ": 已被注册");
                    continue;
                }
                if (terminalsXb.getProtocolId() == null || !terminalsXb.getProtocolId().equals("2")) {
                    failureNum++;
                    bl = false;
                    failureMsg.append("</br>" + failureNum + ",IMEI" + terminalsXb.getImei() + ": 协议错误");
                }
                if (bl) {
                    log.info("开始注册");
                    JSONObject responseBody = null;

                    // aep平台注册
                    if (terminalsXb1.getSignPlatform() == 1) {
                        responseBody = createGuoXinDeviceInAep(appKey, appSecret, masterKey, terminalsXb1);
                        if (Integer.parseInt(responseBody.getString("code")) == 2010115) {
                            log.info("更新数据库");
                            // 已经被注册查询并更新deviceId
                            JSONObject jsonObject = queryDeviceList(appKey, appSecret, masterKey, terminalsXb.getImei());
                            JSONObject resultJsonObject = JSONObject.parseObject(jsonObject.getString("result"));
                            JSONArray list = resultJsonObject.getJSONArray("list");
                            JSONObject device = JSONObject.parseObject(list.get(0).toString());
                            String deviceId = device.getString("deviceId");
                            terminalsXb1.setDeviceId(deviceId);
                            terminalsXbMapper.updateTerminalsXb(terminalsXb1);
                        }
                        if (Integer.parseInt(responseBody.getString("code")) != 0) {
                            failureNum++;
                            failureMsg.append("</br>").append(failureNum).append(",IMEI").append(terminalsXb1.getImei()).append(": ").append(responseBody.getString("msg"));
                        } else {
                            String deviceId = JSONObject.parseObject(responseBody.getString("result")).getString("deviceId");
                            terminalsXb1.setDeviceId(deviceId);
                            terminalsXbMapper.updateTerminalsXb(terminalsXb1);
                            successNum++;
                            successMsg.append("<br/>").append(successNum).append("、IMEI ").append(terminalsXb1.getImei()).append(": 注册成功");
                        }
                    }


                    // OneNET平台注册
                    if (terminalsXb1.getSignPlatform() == 2) {
                        responseBody = createDeviceInOneNet(terminalsXb1);
                        System.out.println(Integer.parseInt(responseBody.getString("errno")));
                        if (Integer.parseInt(responseBody.getString("errno")) == 6) {
                            JSONObject jsonObject = queryDeviceList2(terminalsXb1);
                            JSONObject resultJsonObject = JSONObject.parseObject(jsonObject.getString("data"));
                            String deviceId = resultJsonObject.getString("id");
                            terminalsXb1.setDeviceId(deviceId);
                            terminalsXbMapper.updateTerminalsXb(terminalsXb1);
                        }
                        if (Integer.parseInt(responseBody.getString("errno")) != 0 || Integer.parseInt(responseBody.getString("errno")) == 6) {
                            failureNum++;
                            failureMsg.append("</br>").append(failureNum).append(",IMEI").append(terminalsXb1.getImei()).append(": ").append(responseBody.getString("msg"));
                        } else {
                            String deviceId = JSONObject.parseObject(responseBody.getString("data")).getString("id");
                            terminalsXb1.setDeviceId(deviceId);
                            terminalsXbMapper.updateTerminalsXb(terminalsXb1);
                            successNum++;
                            successMsg.append("<br/>").append(successNum).append("、IMEI ").append(terminalsXb1.getImei()).append(": 注册成功");
                        }
                    }
                    // 更新redis
                    log.info("更新redis");
                    ElectricityTerminalsXbProtocol terminalsXbProtocol = new ElectricityTerminalsXbProtocol();
                    terminalsXbProtocol.setImei(terminalsXb1.getImei());
                    List<ElectricityTerminalsXbProtocol> terminalsXbProtocols = selectTerminalsXbProtocolList(terminalsXbProtocol);
                    if (!terminalsXbProtocols.isEmpty()) {
                        redisCache.setCacheMapValue(RedisKeyName.terminalInfo + terminalsXbProtocols.get(0).getSupplierId(), terminalsXbProtocols.get(0).getCommunicateAddress(), terminalsXbProtocols.get(0));
                    }
                }
            } catch (Exception e) {
                failureNum++;
                log.info(failureNum + ",IMEI" + terminalsXb1.getImei() + ": 注册失败");
                failureMsg.append("</br>").append(failureNum).append(",IMEI").append(terminalsXb1.getImei()).append(": 注册失败");
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            log.info("很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：" + failureMsg.toString());
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public JSONObject deleteGuoXinDeviceInAep(String appKey, String appSecret, String MasterKey, List<String> deviceIds, String productId) throws Exception {
        AepDeviceManagementClient client = AepDeviceManagementClient.newClient()
                .appKey(appKey).appSecret(appSecret)
                .build();
        try {
            DeleteDeviceByPostRequest request = new DeleteDeviceByPostRequest();
            request.setParamMasterKey(MasterKey);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("productId", productId);
            jsonObject.put("deviceIdList", deviceIds);
            request.setBody(jsonObject.toString().getBytes());
            DeleteDeviceByPostResponse deleteDeviceByPostResponse = client.DeleteDeviceByPost(request);
            System.out.println(deleteDeviceByPostResponse);
            if (deleteDeviceByPostResponse.getStatusCode() == HttpStatus.SUCCESS) {
                return JSONObject.parseObject(new String(deleteDeviceByPostResponse.getBody(), StandardCharsets.UTF_8));
            } else {
                return null;
            }
        } catch (Exception e) {
            log.error("AEP平台删除设备失败", e);
            return null;
        } finally {
            client.shutdown();
        }

    }

    // 查询aep的设备信息
    @Override
    public JSONObject queryDeviceList(String appKey, String appSecret, String MasterKey, String IMEI) {
        AepDeviceManagementClient client = AepDeviceManagementClient.newClient()
                .appKey(appKey).appSecret(appSecret)
                .build();
        QueryDeviceListRequest request = new QueryDeviceListRequest();
        request.setParamMasterKey(MasterKey);
        request.setParamProductId(16902088);
        request.setParamSearchValue(IMEI);
        try {
            QueryDeviceListResponse queryDeviceListResponse = client.QueryDeviceList(request);
            if (queryDeviceListResponse.getStatusCode() != 200) {
                return null;
            }
            return JSONObject.parseObject(new String(queryDeviceListResponse.getBody(), StandardCharsets.UTF_8));
        } catch (Exception e) {
            log.info(e.getMessage());
            return null;
        } finally {
            client.shutdown();
        }
    }

    // 跟据imei在OneNET上查询的设备信息
    @Override
    public JSONObject queryDeviceList2(ElectricityTerminalsXb terminalsXb) {
        try {
            String imei = terminalsXb.getImei();
            String url = "https://api.heclouds.com/devices/getbyimei";
            String sendPost = HttpUtils.sendGetInOneNET(url, imei);
            JSONObject json = JSONObject.parseObject(sendPost);
            if (json.get("errno").equals(0) && json.get("error").equals("succ")) {
                System.out.println(sendPost);
                return json;
            } else {
                return null;
            }
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return null;
    }

    @Override
    public List<AreaTreeTerminalInfo> searchTerminalXB(ElectricityTerminalsXb terminalsXb) {
        return terminalsXbMapper.searchTerminalXB(terminalsXb);
    }

    @Override
    public List<ElectricityTerminalsXb> selectTerminalsXbBySheetsCode(String sheetsCode) {
        LambdaQueryWrapper<ElectricityTerminalsXb> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(sheetsCode)) {
            ArrayList<String> sheetsCodeList = CollUtil.toList(sheetsCode.split(","));
            queryWrapper.in(ElectricityTerminalsXb::getSheetsCode, sheetsCodeList);
        }
        queryWrapper.isNotNull(ElectricityTerminalsXb::getSheetsCode);
        queryWrapper.eq(ElectricityTerminalsXb::getTerminalMark, 1);
        return terminalsXbMapper.selectList(queryWrapper);
    }

    /**
     * 销表
     *
     * @param terminalsXb
     * @return
     */
    @Override
    public boolean cancelTerminal(ElectricityTerminalsXb terminalsXb, String operator) {
        terminalsXb.setTerminalMark(0);
        int i = terminalsXbMapper.updateTerminalsXb(terminalsXb);
        Account account = Account.builder().sheetsCode(terminalsXb.getSheetsCode()).terminalId(terminalsXb.getTerminalId())
                .userId(terminalsXb.getUserId()).terminalType(2L).operator(operator).locationNb(terminalsXb.getLocationNb()).tenantId(terminalsXb.getTenantId()).build();
        final int flag = accountMapper.insertAccount(account);
        return flag != 0 && i != 0;
    }

    /**
     * 查询小档案列表
     *
     * @param terminalsXb 小档案
     * @return 小档案
     */
    @Override
    public List<TerminalsXbRGView> selectTerminalsXbListAndRealtimegatherdata(ElectricityTerminalsXb terminalsXb) {
        return terminalsXbMapper.selectTerminalsXbListAndRealtimegatherdata(terminalsXb);
    }

    @Override
    public ElectricityTerminalsXb getByLocationNb(String locationNb) {
        return terminalsXbMapper.selectOne(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                .eq(ElectricityTerminalsXb::getLocationNb, locationNb));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeTerminalXb(ElectricityTerminalsXb terminalsXb) {
        if (Objects.equals(terminalsXb.getProtocolId(), QIANBAOTONG_PROTOCOL_ID)) {
            if (terminalsXb.getConcentratorId() == null) {
                throw new ServiceException("该协议集中器不能为空");
            }
            ElectricityTerminalsXb old = terminalsXbMapper.selectById(terminalsXb.getId());
            if (old.getConcentratorId() == null) {
                // 如果原来没有集中器，换表后要重新编号
                int maxSeq = terminalsXbMapper.selectMaxMeterSeq(QIANBAOTONG_PROTOCOL_ID, terminalsXb.getConcentratorId());
                int meterSeq = maxSeq + 1;
                terminalsXb.setMeterSeq(meterSeq);
                terminalsXb.setCommunicateAddress(terminalsXb.getConcentratorId() + "-" + meterSeq);
            } else if (!old.getConcentratorId().equals(terminalsXb.getConcentratorId())) {
                throw new ServiceException("换表前后集中器须保持一致");
            } else {
                // 千宝通协议换表时需要将原来的表序号带上，防止修改了这个字段，再查下数据库
                terminalsXb.setMeterSeq(old.getMeterSeq());
                terminalsXb.setCommunicateAddress(old.getCommunicateAddress());
            }

        }
        ElectricityTerminalsXb terminalsXb1 = terminalsXbMapper.selectOne(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                .eq(ElectricityTerminalsXb::getTerminalId, terminalsXb.getNewTerminalId())
                .eq(ElectricityTerminalsXb::getTerminalMark, 1)
                .last("limit 1"));
        ElectricityTerminalsXb terminalsXb2 = terminalsXbMapper.selectOne(new LambdaQueryWrapper<ElectricityTerminalsXb>()
                .eq(ElectricityTerminalsXb::getImei, terminalsXb.getNewImei())
                .eq(ElectricityTerminalsXb::getTerminalMark, 1)
                .last("limit 1"));
        if (terminalsXb1 != null && !terminalsXb.getId().equals(terminalsXb1.getId())) {
            throw new ServiceException("新设备编号已存在");
        }
        if (terminalsXb2 != null && !terminalsXb.getId().equals(terminalsXb2.getId())) {
            throw new ServiceException("新IMEI号已存在");
        }
        terminalsXb.setTerminalMark(0);
        terminalsXb.setChangeMark(1);
        terminalsXbMapper.updateTerminalsXb(terminalsXb);
        Account account = Account.builder().sheetsCode(terminalsXb.getSheetsCode()).terminalId(terminalsXb.getTerminalId())
                .userId(terminalsXb.getUserId()).terminalType(2L).operator(SecurityUtils.getUsername())
                .locationNb(terminalsXb.getLocationNb()).tenantId(terminalsXb.getTenantId()).build();
        accountMapper.insertAccount(account);
        Replace replace = Replace.builder().changeTime(new Date()).newTerminalId(terminalsXb.getNewTerminalId())
                .oldTerminalId(terminalsXb.getTerminalId()).oldSupplierId(terminalsXb.getSupplierId()).newSupplierId(terminalsXb.getSupplierId())
                .operator(SecurityUtils.getUsername()).loginUserId(SecurityUtils.getUserId().intValue()).sheetsCode(terminalsXb.getSheetsCode())
                .sheetsId(terminalsXb.getSheetsId()).systemFlag(0).tenantId(terminalsXb.getTenantId()).terminalClassify(2).oldSettlementReading(terminalsXb.getBaseReading())
                .newBaseReading(terminalsXb.getNewBaseReading()).build();
        terminalsXb.setTerminalId(terminalsXb.getNewTerminalId());
        terminalsXb.setImei(terminalsXb.getNewImei());
        terminalsXb.setTerminalMark(1);
        terminalsXb.setChangeMark(0);
        terminalsXb.setBaseReading(terminalsXb.getNewBaseReading());
        terminalsXb.setDeviceId(null);
        terminalsXbMapper.insertTerminalsXb(terminalsXb);
        // 更新redis
        ElectricityTerminalsXbProtocol terminalsXbProtocol = new ElectricityTerminalsXbProtocol();
        terminalsXbProtocol.setImei(terminalsXb.getImei());
        List<ElectricityTerminalsXbProtocol> terminalsXbProtocols = selectTerminalsXbProtocolList(terminalsXbProtocol);
        if (!terminalsXbProtocols.isEmpty()) {
            redisCache.setCacheMapValue(RedisKeyName.terminalInfo + terminalsXbProtocols.get(0).getSupplierId(), terminalsXbProtocols.get(0).getCommunicateAddress(), terminalsXbProtocols.get(0));
        }
        int i = replaceMapper.insertReplace(replace);
        return i > 0;


    }

    @Override
    public void updateAllLocationNb() {
        List<ElectricityTerminalsXb> terminalsXbs = terminalsXbMapper.selectList(new LambdaQueryWrapper<ElectricityTerminalsXb>());
        SnowflakeUtils snowflakeUtils = new SnowflakeUtils(0, 0);
        terminalsXbs.forEach(terminalsXb -> {
            String locationNb = String.valueOf(snowflakeUtils.nextId());
            terminalsXb.setLocationNb(locationNb);
            terminalsXbMapper.updateTerminalsXb(terminalsXb);
        });

    }

    @Override
    public void updateDeviceId(ElectricityTerminalsXb terminalsXb) {
        terminalsXbMapper.updateTerminalsXb(terminalsXb);
        ElectricityTerminalsXbProtocol terminalsXbProtocol = new ElectricityTerminalsXbProtocol();
        terminalsXbProtocol.setImei(terminalsXb.getImei());
        List<ElectricityTerminalsXbProtocol> terminalsXbProtocols = selectTerminalsXbProtocolList(terminalsXbProtocol);
        if (terminalsXbProtocols.size() != 0) {
            redisCache.setCacheMapValue(RedisKeyName.terminalInfo + terminalsXbProtocols.get(0).getSupplierId(), terminalsXbProtocols.get(0).getCommunicateAddress(), terminalsXbProtocols.get(0));
        }
    }

    /**
     * 小表过户
     *
     * @param usersXb    新的小表用户档案
     * @param terminalId 小表id
     * @param newUser    是否新建用户
     * @return 是否过户成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeTerminalUser(ElectricityUsersXb usersXb, String terminalId, boolean newUser) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        ElectricityTerminalsXb terminalsXb = terminalsXbMapper.selectTerminalsXbByTerminalID(terminalId);
        if (terminalsXb == null) {
            throw new ServiceException(String.format("terminalId：%s，设备不存在！", terminalId));
        }
        String oldUserId = terminalsXb.getUserId();
        String nowUserId = usersXb.getUserId();
        if (StringUtils.equals(oldUserId, nowUserId)) {
            throw new ServiceException("新用户编号不能与旧用户编号一样！");
        }
        LambdaQueryWrapper<ElectricityUsersXb> checkExistWrapper = Wrappers.lambdaQuery();
        if (newUser) {
            checkExistWrapper.eq(ElectricityUsersXb::getUserId, nowUserId);
            ElectricityUsersXb exist = usersXbMapper.selectOne(checkExistWrapper);
            if (exist != null) {
                throw new ServiceException(String.format("新建用户编号%s已存在！", nowUserId));
            }
        } else {
            checkExistWrapper.eq(ElectricityUsersXb::getUserId, nowUserId)
                    .eq(ElectricityUsersXb::getDelFlag, 0);
            ElectricityUsersXb exist = usersXbMapper.selectOne(checkExistWrapper);
            if (exist == null) {
                throw new ServiceException(String.format("输入的已有用户编号%s不存在或已被删除！", nowUserId));
            }
        }

        int rows1;
        if (newUser) {
            // 新增小表用户
            usersXb.setUserMark(1);
            usersXb.setCreateTime(new Date());
            usersXb.setCreateBy(user.getUserName());
            usersXb.setDelFlag(0);
            usersXb.setTenantId(terminalsXb.getTenantId());
            rows1 = usersXbMapper.insert(usersXb);
        } else {
            // 更新小表用户
            LambdaQueryWrapper<ElectricityUsersXb> updateWrapper = Wrappers.lambdaQuery();
            updateWrapper.eq(ElectricityUsersXb::getUserId, nowUserId);
            ElectricityUsersXb updateValue = new ElectricityUsersXb();
            updateValue.setUserMark(1);
            updateValue.setDelFlag(0);
            updateValue.setUpdateBy(user.getUserName());
            updateValue.setUpdateTime(new Date());
            rows1 = usersXbMapper.update(updateValue, updateWrapper);
        }

        // 过户
        ElectricityTerminalsXb updateXb = ElectricityTerminalsXb.builder().id(terminalsXb.getId()).userId(nowUserId).updateBy(user.getUserName()).updateTime(new Date()).build();
        int rows2 = terminalsXbMapper.updateTerminalsXb(updateXb);
        // 记录过户信息
        UserChangeXbLog log = UserChangeXbLog.builder().oldUserId(oldUserId).userId(nowUserId).terminalId(terminalId).build();
        log.setCreateBy(user.getUserName());
        log.setCreateTime(new Date());
        userChangeXbLogMapper.insert(log);
        return rows1 > 0 && rows2 > 0;
    }

    @Override
    public boolean updateRedisCache(ElectricityTerminalsXb xb) {
        List<ElectricityTerminalsXbProtocol> terminalsXbProtocols = selectTerminalsXbProtocolList(xb);
        for (ElectricityTerminalsXbProtocol protocol : terminalsXbProtocols) {
            redisCache.setCacheMapValue(RedisKeyName.terminalInfo + protocol.getSupplierId(), protocol.getCommunicateAddress(), protocol);
        }
        return true;
    }

    @Override
    public ElectricityTerminalsXb selectTerminalsXbByTerminalID(String terminalID) {
        return terminalsXbMapper.selectTerminalsXbByTerminalID(terminalID);
    }

    @Override
    public boolean batchUpdateTerminalsXb(List<BatchUpdateTerminalsXb> list) {
        try {
            SysUser sysUser = SecurityUtils.getLoginUser().getUser();
            LambdaQueryWrapper<MeterSheets> meterSheetsWrapper = Wrappers.lambdaQuery();
            meterSheetsWrapper.eq(MeterSheets::getDelFlag, 0);
            meterSheetsWrapper.select(MeterSheets::getId, MeterSheets::getSheetsCode);
            List<MeterSheets> allMeterSheets = meterSheetsMapper.selectList(meterSheetsWrapper);
            Map<String, Integer> allSheetsCodeIdMap = new HashMap<>(allMeterSheets.size());
            allMeterSheets.forEach(e -> allSheetsCodeIdMap.put(e.getSheetsCode(), e.getId().intValue()));
            boolean flag = true;
            for (BatchUpdateTerminalsXb update : list) {
                LambdaQueryWrapper<ElectricityUsersXb> usersXbWrapper = Wrappers.lambdaQuery();
                usersXbWrapper.eq(ElectricityUsersXb::getUserId, update.getUserId());
                usersXbWrapper.eq(ElectricityUsersXb::getTenantId, update.getTenantId());
                usersXbWrapper.eq(ElectricityUsersXb::getDelFlag, 0);
                usersXbWrapper.last("limit 1");
                ElectricityUsersXb usersXb = usersXbMapper.selectOne(usersXbWrapper);
                usersXb = usersXb == null ? new ElectricityUsersXb() : usersXb;
                usersXb.setUserName(update.getUserName());
                usersXb.setUserCode(update.getUserCode());
                usersXb.setIdType(update.getIdType());
                usersXb.setUserPhone(update.getUserPhone());
                usersXb.setUserMark(1);
                usersXb.setUserAddress(update.getUserAddress());
                if (usersXb.getId() == null) {
                    usersXb.setCreateBy(sysUser.getUserName());
                    usersXb.setCreateTime(new Date());
                    usersXb.setUserId(update.getUserId());
                    usersXb.setTenantId(update.getTenantId());
                    usersXb.setDelFlag(0);
                    usersXbMapper.insert(usersXb);
                } else {
                    usersXb.setUpdateBy(sysUser.getUserName());
                    usersXb.setUpdateTime(new Date());
                    usersXbMapper.updateById(usersXb);
                }
                // 更新 户表档案
                LambdaQueryWrapper<ElectricityTerminalsXb> terminalsXbWrapper = Wrappers.lambdaQuery();
                terminalsXbWrapper.eq(ElectricityTerminalsXb::getTerminalId, update.getTerminalId());
                terminalsXbWrapper.eq(ElectricityTerminalsXb::getSupplierId, update.getSupplierId());
                terminalsXbWrapper.eq(ElectricityTerminalsXb::getDelFlag, 0);
                terminalsXbWrapper.eq(ElectricityTerminalsXb::getTerminalMark, 1);
                terminalsXbWrapper.last("limit 1");
                ElectricityTerminalsXb terminalsXb = terminalsXbMapper.selectOne(terminalsXbWrapper);
                if (terminalsXb != null) {
                    terminalsXb.setUpdateBy(sysUser.getUserName());
                    terminalsXb.setUpdateTime(new Date());
                    terminalsXb.setUserId(update.getUserId());
                    terminalsXb.setUserName(update.getUserName());
                    terminalsXb.setTenantId(update.getTenantId());
                    terminalsXb.setSheetsCode(update.getSheetsCode());
                    terminalsXb.setSheetsId(allSheetsCodeIdMap.get(update.getSheetsCode()));
                    String result = this.updateTerminalsXb(terminalsXb);
                    if (!"更新成功".equals(result)){
                        log.error("批量更新户表档案和用户数据出错：{}，terminalId：{}", result, update.getTerminalId());
                        flag = false;
                    }
                }
            }
            return flag;
        } catch (Exception e) {
            log.error("批量更新户表档案和用户数据出错", e);
        }
        return false;
    }
}
